#include "msg_core.h"
#include "UIContainer.h"
#include "UILabel.h"
#include "win_gdi.h"
#include <map>

// global var
std::map<void *, DuiWinManager *> g_msg_mgrs;

/// @brief shell的消息自定义分发处理函数
/// @param mgr 窗口管理器
/// @param msg 消息ID
/// @param wParam
/// @param lParam
/// @return 如果返回true，消息将由系统默认处理，否则消息将被自定义处理
bool shell_msg_dispense(DuiWinManager *mgr, DUI_WIN_MSG msg, void *pEvent, int lParam)
{
    switch (msg)
    {
    case DUI_WIN_MSG_CREATE: {
        printf("[%d] create\n", msg);
        shell_mgr_build_render(mgr);
    }
    break;
    case DUI_WIN_MSG_MOUSE_MOVE: {
        auto mouseEvent = (DuiEventMouse *)pEvent;
        auto pHover = (UIContainer *)shell_mgr_check_ui(mgr, mouseEvent->x, mouseEvent->y);
        if (pHover != mgr->pCurHoverUI)
        {
            if (mgr->pCurHoverUI != nullptr)
                ((UILabel *)mgr->pCurHoverUI)->onMouseLeave();
            mgr->pCurHoverUI = pHover;
            if (pHover != nullptr)
                ((UILabel *)pHover)->onMouseEnter();
        }
        else
        {
            pHover->onMouseMove(mouseEvent->x, mouseEvent->y);
        }
    }
    break;
    case DUI_WIN_MSG_MOUSE_WHEEL:
    case DUI_WIN_MSG_MOUSE_DBCLICK:
    case DUI_WIN_MSG_MOUSE_KUP:
    case DUI_WIN_MSG_MOUSE_KDOWN: {
        auto mouseEvent = (DuiEventMouse *)pEvent;
        auto pFocus = (UIContainer *)shell_mgr_check_ui(mgr, mouseEvent->x, mouseEvent->y);
        if (pFocus != nullptr)
        {
            mgr->pCurFocusUI = pFocus;
            switch (msg)
            {
            case DUI_WIN_MSG_MOUSE_WHEEL:
                pFocus->onMouseWheel(mouseEvent->wheel,mouseEvent->x, mouseEvent->y);
                break;
            case DUI_WIN_MSG_MOUSE_KUP:
                pFocus->onMouseUp(mouseEvent->x, mouseEvent->y);
                break;
            case DUI_WIN_MSG_MOUSE_KDOWN:
                pFocus->onMouseDown(mouseEvent->x, mouseEvent->y);
                break;
            default:
                break;
            }
        }
        else
        {
            mgr->pCurFocusUI = nullptr;
        }
    }
    break;
    case DUI_WIN_MSG_COMMAND: {
        auto cmdEvent = (DuiEventCommand *)pEvent;
        printf("[%d] cmd: %d, from hwnd: %d\n", msg, cmdEvent->cmd, cmdEvent->fromHwnd);
    }
    break;
    case DUI_WIN_MSG_KBD_UP:
    case DUI_WIN_MSG_KBD_DOWN:
    case DUI_WIN_MSG_KBD_CHAR: {
        auto keyEvent = (DuiEventKbd *)pEvent;
        if (mgr->pCurFocusUI != nullptr)
        {
            auto pFocus = (UIContainer *)mgr->pCurFocusUI;
            switch (msg)
            {
            case DUI_WIN_MSG_KBD_UP:
                pFocus->onKeyUp(keyEvent->key);
                break;
            case DUI_WIN_MSG_KBD_DOWN:
                pFocus->onKeyDown(keyEvent->key);
                break;
            case DUI_WIN_MSG_KBD_CHAR:
                pFocus->onKeyChar(keyEvent->key);
                break;
            default:
                break;
            }
        }
    }
    break;
    case DUI_WIN_MSG_IME_CHAR: {
        auto keyEvent = (DuiEventKbd *)pEvent;
        if (mgr->pCurFocusUI != nullptr)
        {
            auto pFocus = (UIContainer *)mgr->pCurFocusUI;
            pFocus->onImeChar(keyEvent->key);
        }
        return false;
    }
    break;
    case DUI_WIN_MSG_CONTEXTMENU: {
        auto menuEvent = (DuiEventContextMenu *)pEvent;
        printf("[%d] menu: %d, x: %d, y: %d\n", msg, menuEvent->button, menuEvent->x, menuEvent->y);
    }
    break;
    case DUI_WIN_MSG_MOVE: {
        // auto moveEvent = (DuiEventMove*)pEvent;
        // printf("[%d] x: %d, y: %d\n", msg, moveEvent->x, moveEvent->y);
    }
    break;
    case DUI_WIN_MSG_RESIZE: {
        auto resizeEvent = (DuiEventResize *)pEvent;
        // printf("[%d] w: %d, h: %d\n", msg, resizeEvent->w, resizeEvent->h);

        if (mgr->pRoot != nullptr)
        {
            auto pRoot = (UILabel *)mgr->pRoot;
            pRoot->setSize(resizeEvent->w, resizeEvent->h);
            pRoot->setNeedUpdate(true);
        }
    }
    break;
    case DUI_WIN_MSG_ACTIVATE: {
        auto activeEvent = (DuiEventActive *)pEvent;
        printf("[%d] active: %d\n", msg, activeEvent->active);
    }
    break;
    case DUI_WIN_MSG_SHOW: {
        auto showEvent = (DuiEventShow *)pEvent;
        printf("[%d] show: %d\n", msg, showEvent->show);
    }
    break;
    case DUI_WIN_MSG_CLOSE: {
        printf("[%d] try close, you can return false to block it!\n", msg);
        // return false;
    }
    break;

    case DUI_WIN_MSG_DESTROY: {
        printf("[%d] destroy\n", msg);
        render_end(mgr);
        render_destroy();
    }
    break;
    case DUI_WIN_MSG_COPYDATA: {
        auto copyDataEvent = (DuiEventCopyData *)pEvent;
        printf("[%d] copyData: %d, %d\n", msg, copyDataEvent->type, copyDataEvent->len);
    }
    break;
    case DUI_WIN_MSG_PAINT: {
        // printf("[%d] paint\n", msg);
    }
    break;

    default:
        // printf("shell_msg_dispense: [%d] %d => %d, %d\n", mgr->hWin, msg, pEvent, lParam);
        break;
    }

    return true;
}

void shell_mgr_init(DuiWinManager *mgr)
{
    if (mgr == nullptr)
    {
        return;
    }
    mgr->hWin = nullptr;
    mgr->hInst = nullptr;
    mgr->default_msg_dispense = shell_msg_dispense;
    mgr->hdc = nullptr;
    mgr->default_paint_dispense = render_draw;
    mgr->pRoot = nullptr;
    mgr->active = false;
    mgr->isMinimized = false;
    mgr->isShow = false;

    mgr->pCurFocusUI = nullptr;
    mgr->pCurHoverUI = nullptr;
}

bool shell_mgr_register(DuiWinManager *mgr)
{
    if (mgr == nullptr || mgr->hWin == nullptr)
    {
        return false;
    }
    g_msg_mgrs.insert(std::make_pair(mgr->hWin, mgr));
    return true;
}

void shell_mgr_unregister(DuiWinManager *mgr)
{
    if (mgr == nullptr || mgr->hWin == nullptr)
    {
        return;
    }
    g_msg_mgrs.erase(mgr->hWin);
}

bool shell_mgr_find(void *hWin, DuiWinManager **mgr)
{
    if (hWin == nullptr || mgr == nullptr)
    {
        return false;
    }
    auto it = g_msg_mgrs.find(hWin);
    if (it != g_msg_mgrs.end())
    {
        *mgr = it->second;
        return true;
    }
    return false;
}

void shell_mgr_build_render(DuiWinManager *mgr)
{
    render_init();

    // root
    auto root = new UILabel();
    root->setName("root");
    root->setRect(DuiRect{0, 0, mgr->rect.w, mgr->rect.h});
    root->setBackgroundColor(DuiColor{255, 0, 255, 255});
    root->setBorderImage("9ge.png");
    root->setBorderImageCorner(DuiCorner{18, 18, 17, 17});
    mgr->pRoot = root;
}

// 深度优先遍历
UIContainer *_ui_check_pos(UIContainer *pUI, int x, int y)
{
    if (pUI == nullptr)
        return nullptr;

    // 从后往前遍历子控件，保证最顶层的控件在最前面
    for (int i = pUI->getChildCount() - 1; i >= 0; i--)
    {
        auto pChild = pUI->getChild(i);
        auto pSel = _ui_check_pos(pChild, x, y);
        if (pSel != nullptr)
        {
            return pSel;
        }
    }
    if (pUI->getVisible() && pUI->isInContainer(x, y))
    {
        return pUI;
    }
    return nullptr;
}

void *shell_mgr_check_ui(DuiWinManager *mgr, int x, int y)
{
    auto pRoot = (UILabel *)mgr->pRoot;
    auto pUI = _ui_check_pos(pRoot, x, y);
    // if (pUI != nullptr)
    // {
    //     auto rc = pUI->getRect();
    //     printf("check ui (%d, %d), %s, %s\r\n", rc.x, rc.y, pUI->getName().c_str(), pUI->getUIType().c_str());
    // }
    return pUI;
}
